// tnxvue.js
/**
 * 基于Vue的扩展支持
 */
import Vue from 'vue';
import tnxcore from '@truenewx/tnxcore/src/tnxcore.js';
import validator from './tnxvue-validator';
import buildRouter from './tnxvue-router';
import Text from './text';
import Percent from './percent';

import './tnxvue.css';

function getDefaultDialogButtons(type, click, theme) {
    if (click !== false) {
        if (type === 'confirm') {
            return [{
                text: '确定',
                type: theme || 'primary',
                click(close) {
                    if (typeof click === 'function') {
                        return click.call(this, true, close);
                    }
                }
            }, {
                text: '取消',
                click(close) {
                    if (typeof click === 'function') {
                        return click.call(this, false, close);
                    }
                }
            }];
        } else {
            return [{
                text: '确定',
                type: theme || 'primary',
                click(close) {
                    if (typeof click === 'function') {
                        return click.call(this, close);
                    }
                }
            }];
        }
    }
    return [];
}

export const build = tnxcore.build;

export default build('tnxvue', () => {
    const tnxvue = Object.assign({}, tnxcore, {
        components: {
            Div: {
                name: 'TnxvueDiv',
                template: '<div><slot></slot></div>'
            },
            Span: {
                name: 'TnxvueSpan',
                template: '<span><slot></slot></span>'
            },
            Text,
            Percent,
        },
        buildRouter,
        install(Vue) {
            let components = this.components;
            Object.keys(components).forEach(key => {
                const component = components[key];
                Vue.component(component.name, component);
            });
            this.libs.Vue = Vue;
        },
        dialog(content, title, buttons, options, contentProps) {
            // 默认不实现，由UI框架扩展层实现
            throw new Error('Unsupported function');
        },
        open(component, props, options) {
            if (component.methods.dialog) {
                options = Object.assign({}, component.methods.dialog(props), options);
            } else {
                options = options || {};
            }
            const title = component.title || options.title;
            const buttons = options.buttons || getDefaultDialogButtons(options.type, options.click, options.theme);
            if (options.buttonText) {
                if (!Array.isArray(options.buttonText)) {
                    options.buttonText = [options.buttonText];
                }
                for (let i = 0; i < buttons.length; i++) {
                    let buttonText = options.buttonText[i];
                    if (buttonText) {
                        buttons[i].text = buttonText;
                    }
                }
            }
            delete options.title;
            delete options.type;
            delete options.click;
            return this.dialog(component, title, buttons, options, props);
        }
    });

    Object.assign(tnxvue.util, {
        /**
         * 判断指定对象是否组件实例
         * @param obj 对象
         * @returns {boolean} 是否组件实例
         */
        isComponent: function (obj) {
            return (typeof obj === 'object') && (typeof obj.data === 'function') && (typeof obj.render === 'function');
        }
    });

    tnxvue.app.isProduction = function () {
        try {
            return !(process && process.env && process.env.NODE_ENV !== 'production');
        } catch (e) {
            // process未定义时会出错，此时为生产模式
            return true;
        }
    };

    tnxvue.app.eventBus = new Vue();

    // 元数据到async-validator组件规则的转换处理
    tnxvue.app.validator = validator;
    tnxvue.app.rpc.getMeta =
        tnxvue.util.function.around(tnxvue.app.rpc.getMeta, function (getMeta, url, callback, app) {
            return getMeta.call(tnxvue.app.rpc, url, function (meta) {
                if (meta) { // meta已被缓存，所以直接修改其内容，以便同步缓存
                    meta.$rules = validator.getRules(meta);
                    if (typeof callback === 'function') {
                        callback.call(this, meta);
                    }
                }
            }, app);
        });

    Object.assign(tnxvue.app.page, {
        // TODO 路由缓存迁移至tnxvue-router.js中
        startCache: function (router, model, intervalMillis, ignoredFields) {
            if (localStorage && intervalMillis && intervalMillis > 1000) { // 缓存间隔必须超过1秒
                let path = this._readCache(router, undefined, function (cache) {
                    Object.assign(model, cache.model);
                });

                if (path) {
                    let _this = this;
                    let intervalId = setInterval(() => {
                        _this._storeCache(router, path, intervalId, model, ignoredFields);
                    }, intervalMillis);
                }
            }
            return model;
        },
        _readCache: function (router, path, callback) {
            if (localStorage) {
                path = path || router.app.$route.path || '/';
                let cache = localStorage[path];
                if (cache) {
                    cache = window.tnx.util.string.parseJson(cache);
                    if (typeof callback === 'function') {
                        callback.call(this, cache);
                    }
                }
                return path;
            }
        },
        _storeCache: function (router, path, intervalId, model, ignoredFields) {
            if (path && intervalId) {
                let data = {};
                if (Array.isArray(ignoredFields) && ignoredFields.length) {
                    Object.keys(model).forEach(key => {
                        if (!ignoredFields.contains(key)) {
                            data[key] = model[key];
                        }
                    });
                } else {
                    data = model;
                }
                localStorage[path] = tnxvue.util.string.toJson({
                    intervalId: intervalId,
                    model: data,
                    ignored: ignoredFields,
                });
            }
        },
        saveCache: function (router, model) {
            let intervalId;
            let ignoredFields;
            let path = this._readCache(router, undefined, function (cache) {
                intervalId = cache.intervalId;
                ignoredFields = cache.ignored;
            });
            this._storeCache(router, path, intervalId, model, ignoredFields);
        },
        stopCache: function (router, path) {
            return this._readCache(router, path, function (cache) {
                clearInterval(cache.intervalId);
            });
        },
        clearCache: function (router) {
            let path = this.stopCache(router);
            if (path) {
                delete localStorage[path];
            }
        },
        /**
         * 前端页面模型转换为后端命令模型，检查文件上传是否完成，去掉后端不需要的多余字段，转换多层嵌入字段数据使其符合服务端命令模型的基本要求
         * @param model 前端页面模型
         * @param refs 页面中的组件引用集
         * @param validFieldNames 有效的字段名称集，如有指定则清除模型中的无效字段
         */
        toCommandModel: function (vm, model, validFieldNames) {
            let result = {};
            if (model) {
                if (vm.$refs) {
                    let refKeys = Object.keys(vm.$refs);
                    for (let refKey of refKeys) {
                        let ref = vm.$refs[refKey];
                        if (typeof ref.getStorageUrl === 'function') {
                            if (ref.validateUploaded() === false) {
                                return null;
                            }
                        }
                    }
                }
                let fieldNames = Object.keys(model);
                for (let fieldName of fieldNames) {
                    if (!validFieldNames || !validFieldNames.length || validFieldNames.contains(fieldName)) {
                        if (fieldName.contains('__')) {
                            let path = fieldName.replace('__', '.');
                            tnxvue.util.object.setValue(result, path, model[fieldName]);
                        } else {
                            result[fieldName] = model[fieldName];
                        }
                    }
                }
            }
            return result;
        },
        /**
         * 转换多层嵌入字段数据使其符合前端页面模型的基本要求
         * @param model 服务端视图模型
         */
        toPageModel: function (model) {
            let expanded = this._expandRefFields(model);
            while (expanded) {
                expanded = this._expandRefFields(model);
            }
            return model;
        },
        _expandRefFields: function (model) {
            let expanded = false;
            Object.keys(model).forEach(key => {
                let value = model[key];
                if (value && typeof value === 'object') {
                    Object.keys(value).forEach(refKey => {
                        model[key + '__' + refKey] = value[refKey];
                    });
                    delete model[key];
                    expanded = true;
                }
            });
            return expanded;
        }
    });

    /**
     * 页面级缓存支持
     */
    tnxvue.app.page.cache = {
        _getName: function (key) {
            return 'cache_' + key;
        },
        get: function (vm, key, defaultValue) {
            let name = this._getName(key);
            let cache = vm.$root[name];
            if (cache === undefined) {
                cache = defaultValue;
                vm.$root[name] = cache;
            }
            return cache;
        },
        set: function (vm, key, value) {
            let name = this._getName(key);
            if (value === undefined) {
                delete vm.$root[name];
            } else {
                vm.$root[name] = value;
            }
        }
    }

    Vue.use(tnxvue);

    return tnxvue;
});
